from django_dynamic_fixture import new, get, DynamicFixture as F, print_field_values

# Models:

from django.db import models

class ModelA(models.Model): pass

class ModelY(models.Model):
    other_text = models.CharField()
    other_list = models.ManyToManyField('ModelA')

class ModelX(models.Model):
    some_text = models.CharField(null=True)
    parent_left = models.ForeingKey('self')
    y_reference = models.ForeingKey('ModelY')
    list_a = models.ManyToManyField('ModelA')

# Summary:

# DynamicFixture (F): receive arguments and create model instances.
# new: it is just a wrapper: it creates a F to create a not saved model instance.
# get: basically, call the new method and save the instance. You can set ManyToMany fields only after the instance is saved.

# Examples:

instance_of_modelx = new(ModelX)
assert instance_of_modelx.some_text != None
assert instance_of_modelx.parent_left != None
assert instance_of_modelx.parent_left.parent_left == None
assert instance_of_modelx.id == None # new do not save the instance
assert instance_of_modelx.y_reference.id != None # save dependencies by default
assert len(instance_of_modelx.list_a.all()) == 0 # do not create many2many fields by default

instance_of_modelx = new(ModelX, fill_nullable_fields=False) # default = True
assert instance_of_modelx.some_text == None

# you can ignore fields, but do not ignore required fields (with null=False).
instance_of_modelx = get(ModelX, ignore_fields=['some_text'])
assert instance_of_modelx.some_text == None

# Very nice feature to work with trees
instance_of_modelx = new(ModelX, number_of_laps=2) # default = 1
assert instance_of_modelx.parent_left != None
assert instance_of_modelx.parent_left.parent_left != None
assert instance_of_modelx.parent_left.parent_left.parent_left == None

# This feature is specially useful to test search methods
instance_of_modelx = new(ModelX, some_text='some fixed data') # attribute accepts static data
assert instance_of_modelx.some_text == 'some fixed data'

# Use this with attention. First, check for design mistakes
instance_of_modelx = new(ModelX, id=99999) # you can define the id too
assert instance_of_modelx.id == 99999)

# You can create your own function to create data..
instance_of_modelx = new(ModelX, some_text=lambda field: field.name) # attribute accepts callables
assert instance_of_modelx.some_text == 'some_text')

# Use this with attention, you can get an error if you try to save an instance with not saved dependencies
instance_of_modelx = new(ModelX, persist_dependencies=False)
assert instance_of_modelx.y_reference.id == None

instance_of_modelx = get(ModelX) # get save the model instance
assert instance_of_modelx.id != None

instance_of_modelx = get(ModelX, list_a=2) # Many2Many can receive a number of instances to be created
assert len(instance_of_modelx.list_a.all()) == 2

instance_of_modelx = get(ModelX, list_a=[F(), F(), F()]) # Many2Many can receive a list of DynamicFixtures
assert len(instance_of_modelx.list_a.all()) == 3

a = get(ModelA)
instance_of_modelx = get(ModelX, list_a=[F(), a, F()]) # Many2Many can receive a list of instances
assert len(instance_of_modelx.list_a.all()) == 3

# You can pass arguments to F (DynamicFixture) recursively. This works for ForeignKey and ManyToMany Fields! Easy and customizable!
instance_of_modelx = get(ModelX, parent_left=F(other_text='wow', other_list=2))
assert len(instance_of_modelx.y_reference.other_list.all()) == 2

# for debug:
print_field_values(instance_of_modelx)